﻿using BUGCOME.Infrastructure.Helper;
using BUGCOME.Model.Enum.File;
using BUGCOME.Model.File;
using BUGCOME.Model.File.Dto;
using BUGCOME.Service.File.IServices;
using BUGCOME.ServiceCore.Filters;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using SqlSugar.Extensions;
using System.Security.Cryptography;
using System.Text;

namespace BUGCOME.File.Api.Controllers
{
    /// <summary>
    /// 文件管理API控制器
    /// 支持文件CRUD、上传下载、分片处理及权限控制
    /// </summary>
    [Verify]
    [Route("fileapi/[controller]/[action]")]
    [ApiExplorerSettings(GroupName = "file")]
    public class FileController : BaseController
    {
        /// <summary>
        /// 文件管理基础业务逻辑服务实例
        /// 封装了文件操作的核心业务逻辑，供控制器调用
        /// </summary>
        private readonly IFileBaseService fileService;
        private IWebHostEnvironment webHostEnvironment;
        private OptionsSetting optionsSetting;

        /// <summary>
        /// 初始化FileController实例
        /// 通过依赖注入获取文件管理服务，实现控制器与业务逻辑的解耦
        /// </summary>
        /// <param name="fileService">文件管理基础业务逻辑服务接口实例</param>
        public FileController(IFileBaseService fileService,
            IOptions<OptionsSetting> options,
            IWebHostEnvironment webHostEnvironment)
        {
            this.fileService = fileService;
            this.webHostEnvironment = webHostEnvironment;
            optionsSetting = options.Value;
        }

        #region 基础CRUD
        /// <summary>
        /// 分页查询文件列表
        /// </summary>
        [ActionPermissionFilter(Permission = "tool:file:list")]
        [HttpPost]
        public async Task<IActionResult> List([FromBody] FileQueryDto dto)
        {
            var result = await fileService.SelectFileListAsync(dto);
            return Success(result);
        }

        /// <summary>
        /// 根据ID查询文件详情
        /// </summary>
        [ActionPermissionFilter(Permission = "tool:file:query")]
        [HttpPost]
        public async Task<IActionResult> GetData([FromBody] ParmDto<long> dto)
        {
            if (dto.Value <= 0)
                return ToResponse(ApiResult.Error("文件ID不能为空"));

            var result = await fileService.SelectFileByIdAsync(dto.Value);
            return Success(result);
        }

        /// <summary>
        /// 新增文件元数据
        /// </summary>
        [ActionPermissionFilter(Permission = "tool:file:add")]
        [Log(Title = "文件管理", BusinessType = BusinessType.INSERT)]
        [HttpPost]
        public async Task<IActionResult> AddData([FromBody] FileDto dto)
        {
            if (dto == null)
                return ToResponse(ApiResult.Error("文件信息不能为空"));

            try
            {
                long currentUserId = HttpContext.GetUId();
                var fileId = await fileService.InsertFileAsync(dto, currentUserId);
                return fileId > 0 ? Success(fileId) : ToResponse(ApiResult.Error("新增文件失败"));
            }
            catch (Exception ex)
            {
                return ToResponse(ApiResult.Error(ex.Message));
            }
        }

        /// <summary>
        /// 修改文件信息
        /// </summary>
        [ActionPermissionFilter(Permission = "tool:file:edit")]
        [Log(Title = "文件管理", BusinessType = BusinessType.UPDATE)]
        [HttpPost]
        public async Task<IActionResult> UpdateData([FromBody] FileDto dto)
        {
            if (dto == null || !dto.Id.HasValue || dto.Id.Value <= 0)
                return ToResponse(ApiResult.Error("文件ID不能为空"));

            try
            {
                long currentUserId = HttpContext.GetUId();
                string currentUserName = HttpContext.GetName();
                var affectedRows = await fileService.UpdateFileAsync(dto, currentUserId, currentUserName);
                return affectedRows > 0 ? Success(affectedRows) : ToResponse(ApiResult.Error("修改文件失败"));
            }
            catch (Exception ex)
            {
                return ToResponse(ApiResult.Error(ex.Message));
            }
        }

        /// <summary>
        /// 批量删除文件
        /// </summary>
        [ActionPermissionFilter(Permission = "tool:file:remove")]
        [Log(Title = "文件管理", BusinessType = BusinessType.DELETE)]
        [HttpPost]
        public async Task<IActionResult> Remove([FromBody] ParmDto<string> dto)
        {
            if (string.IsNullOrEmpty(dto.Value))
                return ToResponse(ApiResult.Error("文件ID列表不能为空"));

            long[] fileIds = Common.Tools.SpitLongArrary(dto.Value);
            if (fileIds.Length == 0)
                return ToResponse(ApiResult.Error("文件ID格式不正确"));

            try
            {
                var affectedRows = await fileService.DeleteFileByIdsAsync(fileIds);
                return affectedRows > 0 ? Success(affectedRows) : ToResponse(ApiResult.Error("删除文件失败"));
            }
            catch (Exception ex)
            {
                return ToResponse(ApiResult.Error(ex.Message));
            }
        }
        #endregion

        #region 上传下载
        /// <summary>
        /// 校验文件哈希是否已存在
        /// </summary>
        [HttpPost]
        public async Task<IActionResult> CheckFileHash([FromBody] ParmDto<string> dto)
        {
            var exists = await fileService.CheckFileHashExistsAsync(dto.Value ?? string.Empty);
            return Success(new { exists });
        }

        /// <summary>
        /// 单文件上传
        /// </summary>
        [ActionPermissionFilter(Permission = "tool:file:upload")]
        [Log(Title = "文件上传", BusinessType = BusinessType.UPLOAD)]
        [HttpPost]
        public async Task<IActionResult> Upload([FromForm] UploadDto uploadDto)
        {
            try
            {
                // 参数校验
                if (uploadDto.File == null || uploadDto.File.Length == 0)
                    return ToResponse(ApiResult.Error("上传文件不能为空"));

                if (uploadDto.Quality < 0 || uploadDto.Quality > 100)
                    return ToResponse(ApiResult.Error("压缩质量必须在0-100之间"));

                long currentUserId = HttpContext.GetUId();
                string currentUserName = HttpContext.GetName() ?? "anonymous";

                // 转换存储类型
                StoreType storeType = (StoreType)uploadDto.StorageType;
                FileBase sysFile = null;

                string fileExt = Path.GetExtension(uploadDto.File.FileName).ToLower();
                double fileSize = Math.Round(uploadDto.File.Length / 1024.0, 2); // KB

                // 文件类型验证
                if (optionsSetting.Upload.NotAllowedExt.Contains(fileExt))
                {
                    return ToResponse(ApiResult.Error("上传失败，未经允许上传类型"));
                }

                // 处理文件名
                string finalFileName = await ProcessFileName(uploadDto, uploadDto.File);

                switch (storeType)
                {
                    case StoreType.LOCAL:
                        string savePath = Path.Combine(webHostEnvironment.WebRootPath);
                        if (string.IsNullOrWhiteSpace(uploadDto.FileDir))
                        {
                            uploadDto.FileDir = optionsSetting.StorageSettings.LocalStorage.PathMappings["0"] ?? "";
                        }
                        sysFile = await fileService.SaveFileToLocalAsync(savePath, uploadDto, finalFileName, currentUserId, currentUserName);
                        break;

                    case StoreType.ALIYUN:
                        int AliMaxContentLength = optionsSetting.ALIYUN_OSS.MaxSize;
                        if (string.IsNullOrWhiteSpace(optionsSetting.ALIYUN_OSS.REGIONID))
                        {
                            return ToResponse(ApiResult.Error("阿里云配置文件缺失"));
                        }
                        if ((fileSize / 1024) > AliMaxContentLength)
                        {
                            return ToResponse(ApiResult.Error($"上传文件过大，不能超过 {AliMaxContentLength} MB"));
                        }
                        sysFile = new FileBase(uploadDto.File.FileName, finalFileName, fileExt,fileSize.ObjToInt(), uploadDto.FileDir, currentUserId, currentUserName)
                        {
                            StorageType = (int)StoreType.ALIYUN,
                            FileType = uploadDto.File.ContentType,
                            Status = uploadDto.Status ?? 1,
                        };
                        sysFile = await fileService.SaveFileToAliyunAsync(sysFile, uploadDto, uploadDto.File);
                        if (sysFile.Id <= 0)
                        {
                            return ToResponse(ApiResult.Error("阿里云连接失败"));
                        }
                        break;

                    default:
                        return ToResponse(ApiResult.Error($"不支持的存储类型：{uploadDto.StorageType}"));
                }

                if (sysFile == null)
                {
                    return ToResponse(ApiResult.Error("文件上传失败"));
                }

                return Success(new
                {
                    fileId = sysFile.Id.ToString(),
                    fileName = sysFile.Name,
                    realName = sysFile.RealName,
                    accessUrl = sysFile.AccessUrl,
                    storageType = uploadDto.StorageType,
                    visibility = uploadDto.Visibility
                });
            }
            catch (InvalidDataException ex)
            {
                return ToResponse(ApiResult.Error(ex.Message));
            }
            catch (ArgumentException ex)
            {
                return ToResponse(ApiResult.Error(ex.Message));
            }
            catch (Exception ex)
            {
                return ToResponse(ApiResult.Error($"上传失败：{ex.Message}"));
            }
        }
        /// <summary>
        /// 根据FileNameType处理最终文件名
        /// </summary>
        private async Task<string> ProcessFileName(UploadDto dto, IFormFile file)
        {
            string fileNameWithoutExt = Path.GetFileNameWithoutExtension(file.FileName);
            string fileExt = Path.GetExtension(file.FileName);

            return dto.FileNameType switch
            {
                1 => fileNameWithoutExt, // 原文件名
                2 => string.IsNullOrWhiteSpace(dto.FileName) ? RandomHelper.HashFileName() : dto.FileName, // 自定义名
                3 => RandomHelper.HashFileName(), // 哈希名
                _ => RandomHelper.HashFileName() // 默认哈希名
            };
        }
      
        /// <summary>
        /// 文件下载（区分个人/非个人用户权限）
        /// </summary>
        [HttpGet]
        public async Task<IActionResult> Download(long fileId)
        {
            try
            {
                long userId = HttpContext.GetUId();
                var downloadResult = await fileService.DownloadFileAsync(fileId, userId);
                return File(downloadResult.Stream, downloadResult.ContentType, downloadResult.FileName, true);
            }
            catch (UnauthorizedAccessException ex)
            {
                return ToResponse(ApiResult.Error(403, ex.Message));
            }
            catch (Exception ex)
            {
                return ToResponse(ApiResult.Error(ex.Message));
            }
        }

        /// <summary>
        /// 断点续传下载
        /// </summary>
        [HttpGet]
        public async Task<IActionResult> RangeDownload(long fileId)
        {
            try
            {
                long userId = HttpContext.GetUId();
                var rangeResult = await fileService.RangeDownloadFileAsync(fileId, userId, Request.Headers.Range);

                Response.StatusCode = StatusCodes.Status206PartialContent;
                Response.Headers.Add("Content-Range", rangeResult.ContentRange);
                Response.Headers.Add("Accept-Ranges", "bytes");
                Response.ContentLength = rangeResult.ContentLength;

                return File(rangeResult.Stream, rangeResult.ContentType, rangeResult.FileName, true);
            }
            catch (UnauthorizedAccessException ex)
            {
                return ToResponse(ApiResult.Error(403, ex.Message));
            }
            catch (Exception ex)
            {
                return ToResponse(ApiResult.Error(ex.Message));
            }
        }
        #endregion

        #region 分片上传
        /// <summary>
        /// 分片上传初始化
        /// </summary>
        [ActionPermissionFilter(Permission = "tool:file:upload")]
        [HttpPost]
        public async Task<IActionResult> InitMultipartUpload([FromBody] MultipartUploadInitDto dto)
        {
            try
            {
                long userId = HttpContext.GetUId();
                var initResult = await fileService.InitMultipartUploadAsync(dto, userId);
                return Success(initResult);
            }
            catch (Exception ex)
            {
                return ToResponse(ApiResult.Error(ex.Message));
            }
        }

        /// <summary>
        /// 上传分片
        /// </summary>
        [ActionPermissionFilter(Permission = "tool:file:upload")]
        [HttpPost]
        public async Task<IActionResult> UploadPart([FromForm] MultipartUploadPartDto dto)
        {
            try
            {
                if (dto.File == null || dto.File.Length == 0)
                    return ToResponse(ApiResult.Error("分片文件不能为空"));

                await fileService.UploadPartAsync(dto);
                return Success("分片上传成功");
            }
            catch (Exception ex)
            {
                return ToResponse(ApiResult.Error(ex.Message));
            }
        }

        /// <summary>
        /// 合并分片
        /// </summary>
        [ActionPermissionFilter(Permission = "tool:file:upload")]
        [HttpPost]
        public async Task<IActionResult> CompleteMultipartUpload([FromBody] MultipartUploadCompleteDto dto)
        {
            try
            {
                long userId = HttpContext.GetUId();
                var result = await fileService.CompleteMultipartUploadAsync(dto, userId);
                return Success(result);
            }
            catch (Exception ex)
            {
                return ToResponse(ApiResult.Error(ex.Message));
            }
        }
        #endregion

        #region 统计与权限
        /// <summary>
        /// 获取文件下载统计
        /// </summary>
        [ActionPermissionFilter(Permission = "tool:file:stats")]
        [HttpPost]
        public async Task<IActionResult> GetDownloadStats([FromBody] FileStatsQueryDto dto)
        {
            var stats = await fileService.GetFileDownloadStatsAsync(dto);
            return Success(stats);
        }

        /// <summary>
        /// 校验文件访问权限
        /// </summary>
        [HttpPost]
        public async Task<IActionResult> CheckAccess([FromBody] FileAccessCheckDto dto)
        {
            var accessResult = await fileService.CheckFileAccessAsync(dto.FileId, dto.UserId);
            return Success(new { hasAccess = accessResult.HasAccess, message = accessResult.Message });
        }
        #endregion
    }
}